#include "SystemEventExecutor.h"

using namespace Utility::LoggerLib;

CSystemEventExecutor::CSystemEventExecutor(const wstring& strName) : IExecutor(strName)
{
    SetEventLog();
}

CSystemEventExecutor::~CSystemEventExecutor(void)
{
}

bool CSystemEventExecutor::Reopen()
{
    return true;
}

void CSystemEventExecutor::Close()
{
}

bool CSystemEventExecutor::DoLogging(const LoggingEvent& event)
{
    wstring strMessage = event.FormatWithoutTime();
    strMessage += L"\n";

    WORD wType = GetEventType(event.level);
    LPCTSTR pszTest = strMessage.c_str();

    Report(pszTest, wType);
    return true;
}

void CSystemEventExecutor::SetEventLog(DWORD dwMaxSize, DWORD dwRetention)
{
    HKEY hKey;
    LPCTSTR tszSubKey = _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application");
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszSubKey, 0, KEY_WRITE|KEY_READ, &hKey) == ERROR_SUCCESS)
    {
        RegSetValueEx(hKey, _T("MaxSize"), 0, REG_DWORD, (LPBYTE) &dwMaxSize, sizeof(DWORD));
        RegSetValueEx(hKey, _T("Retention"), 0, REG_DWORD, (LPBYTE) &dwRetention, sizeof(DWORD));
    }

    RegCloseKey(hKey);
}

void CSystemEventExecutor::RegEventSource()
{
    HKEY hKey;
    TCHAR tszSubKey[MAX_PATH] = {};
    
    swprintf_s(tszSubKey, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), m_strName.c_str());
        //CUtil::GetSystemName().c_str());
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszSubKey, 0, KEY_WRITE|KEY_READ, &hKey) != ERROR_SUCCESS)
    {
        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, tszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
        {
            wstring strPath;// = CUtil::GetCurrentDir();

            SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, GENERIC_READ);
            SC_HANDLE hService = OpenService(hSCManager, m_strName.c_str(), GENERIC_READ);

            if (hService != NULL)
            {
                DWORD dwNeeded = 0;
                LPQUERY_SERVICE_CONFIG pBuf = reinterpret_cast<LPQUERY_SERVICE_CONFIG>(_alloca(8*1024));
                QueryServiceConfig(hService, pBuf, 1024 * 8, &dwNeeded);

                strPath = pBuf->lpBinaryPathName; 
            }
            CloseServiceHandle(hService);
            CloseServiceHandle(hSCManager);

            ::RegSetValueEx(hKey, _T("EventMessageFile"), 0, REG_EXPAND_SZ, reinterpret_cast<const BYTE*>(strPath.c_str()), (strPath.length() + 1) * sizeof(TCHAR));

            DWORD data = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; 
            ::RegSetValueEx(hKey, _T("TypesSupported"), 0, REG_DWORD, (LPBYTE) &data, sizeof(DWORD));
        }
    }

    RegCloseKey(hKey);
}

void CSystemEventExecutor::Report(LPCTSTR pszText, WORD wType)
{
    RegEventSource();

    HANDLE hEventSource = RegisterEventSource(NULL, m_strName.c_str());//CUtil::GetSystemName().c_str());

    if (hEventSource != NULL)
    { 
        BOOL b = ReportEvent(hEventSource, wType, 0, 0, NULL, 1, 0, &pszText, NULL);
        DeregisterEventSource(hEventSource); 
    }
}

WORD CSystemEventExecutor::GetEventType(ELOGLEVEL level)
{
    WORD wType = 0;

    switch(level)
    {
    case DEBUG_LEVEL:
        wType = EVENTLOG_INFORMATION_TYPE;
        break;
    case ERROR_LEVEL:
        wType = EVENTLOG_ERROR_TYPE;
        break;
    case WARN_LEVEL:
        wType = EVENTLOG_WARNING_TYPE;
        break;
    case INFO_LEVEL:
        wType = EVENTLOG_INFORMATION_TYPE;
        break;
    default:
        wType = EVENTLOG_AUDIT_FAILURE;
    }

    return wType;
}
